﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DDD;
using Xunit;

namespace DokiDokiTest {
    public class TestCacheArray {

        /// <summary>
        /// 
        /// </summary>
        [Fact]
        public void Test_New1 () {
            var cache = new CacheArray<int> ();

            Assert.Equal (0, cache.CachedCount);
        }

        /// <summary>
        /// キャッシュの追加するテスト
        /// </summary>
        [Fact]
        public void Test_Add () {
            var cache = new CacheArray<int> ();
            var obj1 = new Node ();
            var obj2 = new Node ();

            cache.Add (obj1, 100);
            cache.Add (obj2, 200);

            Assert.Equal (2, cache.CachedCount);
            Assert.Equal (100, cache[obj1]);
            Assert.Equal (200, cache[obj2]);
        }

        /// <summary>
        /// キャッシュの削除するテスト
        /// </summary>
        [Fact]
        public void Test_Remove () {
            var cache = new CacheArray<int> ();
            var obj1 = new Node ();
            var obj2 = new Node ();

            cache.Add (obj1, 100);
            cache.Add (obj2, 200);
            cache.Remove (obj1);
            cache.Remove (obj2);
            cache.Remove (null);
            cache.Remove (obj2);

            Assert.Equal (0, cache.CachedCount);
        }

        /// <summary>
        /// インデクサｰのテスト
        /// </summary>
        /// <remarks>
        /// 存在しないオブジェクトのIDを取得した場合は
        /// デフォルト0が返ってくる(OpenGLだと０はいろいろ都合がいい)。
        /// </remarks>
        [Fact]
        public void Test_Indexer () {
            var cache = new CacheArray<int> ();
            var obj1 = new Node ();
            var obj2 = new Node ();

            cache.Add (obj1, 100);

            Assert.Equal (1, cache.CachedCount);
            Assert.Equal (100, cache[obj1]);
            Assert.Equal (0, cache[obj2]);
        }

        /// <summary>
        /// GCによって不要になったキャッシュが解放される事を確認するテスト
        /// </summary>
        [Fact]
        public void Test_GC () {
            var cache = new CacheArray<int> ();
            var obj = new Node ();

            cache.Add (obj, 100);

            obj = null;
            System.GC.Collect ();

            cache.Release ();

            Assert.Equal (0, cache.CachedCount);
        }

        /// <summary>
        /// GCイベントが呼び出される事を確認するテスト
        /// </summary>
        [Fact]
        public void Test_GCEvents () {
            var cache = new CacheArray<int> ();
            var obj1 = new Node ();
            var obj2 = new Node ();

            cache.Add (obj1, 100);
            cache.Add (obj2, 200);

            var sum = 0;
            cache.ReleaseEvents += delegate (Type keyType, int id) {
                sum += id;
            };

            obj1 = null;
            obj2 = null;
            System.GC.Collect ();

            cache.Release ();

            Assert.Equal (0, cache.CachedCount);
            Assert.Equal (300, sum);
        }

        /// <summary>
        /// GCEventsを2つ設定するテスト(普通はやらない)
        /// </summary>
        [Fact]
        public void Test_GCEvents_2 () {
            var cache = new CacheArray<int> ();
            var obj1 = new Node ();
            var obj2 = new Node ();

            cache.Add (obj1, 100);
            cache.Add (obj2, 200);

            var sum = 0;
            cache.ReleaseEvents += delegate (Type keyType, int id) {
                sum += id;
            };
            cache.ReleaseEvents += delegate (Type keyType, int id) {
                sum += id;
            };

            obj1 = null;
            obj2 = null;
            System.GC.Collect ();

            cache.Release ();

            Assert.Equal (0, cache.CachedCount);
            Assert.Equal (600, sum);
        }

        /// <summary>
        /// 列挙子のテスト
        /// </summary>
        [Fact]
        public void Test_Enumerator(){
            var cache = new CacheArray<int> ();
            var obj1 = new Node ();
            var obj2 = new Node ();
            var obj3 = new Node ();

            cache.Add (obj1, 100);
            cache.Add (obj2, 200);
            cache.Add (obj3, 300);

            var sum = cache.Sum (x => x.Value);

        }

    }
}
